package com.google.code.sms.dao;

import com.google.code.sms.Logger;
import com.google.code.sms.domain.MediaElement;
import com.google.code.sms.domain.Playlist;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Provides database services for play-lists.
 *
 * @author Scott Ware
 */
public class PlaylistDao extends AbstractDao {

    private static final Logger LOG = Logger.getLogger("PlaylistDao");
    private static final String COLUMNS = "id, username, is_public, name, element_count, duration, created, changed";
    private final RowMapper rowMapper = new PlaylistMapper();

    public List<Playlist> getReadablePlaylistsForUser(String username) {

        List<Playlist> result1 = getWritablePlaylistsForUser(username);
        List<Playlist> result2 = query("select " + COLUMNS + " from playlist where is_public", rowMapper);
        List<Playlist> result3 = query("select " + prefix(COLUMNS, "playlist") + " from playlist, playlist_user where "
                + "playlist.id = playlist_user.playlist_id and "
                + "playlist.username != ? and "
                + "playlist_user.username = ?", rowMapper, username, username);

        // Put in sorted map to avoid duplicates.
        SortedMap<Integer, Playlist> map = new TreeMap<>();
        for (Playlist playlist : result1) {
            map.put(playlist.getId(), playlist);
        }
        for (Playlist playlist : result2) {
            map.put(playlist.getId(), playlist);
        }
        for (Playlist playlist : result3) {
            map.put(playlist.getId(), playlist);
        }
        return new ArrayList<>(map.values());
    }

    public List<Playlist> getWritablePlaylistsForUser(String username) {
        return query("select " + COLUMNS + " from playlist where username=?", rowMapper, username);
    }

    public Playlist getPlaylist(int id) {
        return queryOne("select " + COLUMNS + " from playlist where id=?", rowMapper, id);
    }

    public List<Playlist> getAllPlaylists() {
        return query("select " + COLUMNS + " from playlist", rowMapper);
    }

    public synchronized void createPlaylist(Playlist playlist) {
        update("insert into playlist(" + COLUMNS + ") values(" + questionMarks(COLUMNS) + ")",
                null, playlist.getUsername(), playlist.isPublic(), playlist.getName(),
                0, 0, playlist.getCreated(), playlist.getChanged());

        int id = queryForInt("select max(id) from playlist", 0);
        playlist.setId(id);
    }

    public void setElementsInPlaylist(int id, List<MediaElement> elements) {
        update("delete from playlist_element where playlist_id=?", id);
        int duration = 0;
        
        for (MediaElement element : elements) {
            update("insert into playlist_element (playlist_id, media_element_id) values (?, ?)", id, element.getId());
            
            if (element.getMetaData().getDuration() != null) {
                duration += element.getMetaData().getDuration();
            }
        }
        update("update playlist set element_count=?, duration=?, changed=? where id=?", elements.size(), duration, new Date(), id);
    }

    public List<String> getPlaylistUsers(int playlistId) {
        return queryForStrings("select username from playlist_user where playlist_id=?", playlistId);
    }

    public void addPlaylistUser(int playlistId, String username) {
        if (!getPlaylistUsers(playlistId).contains(username)) {
            update("insert into playlist_user(playlist_id,username) values (?,?)", playlistId, username);
        }
    }

    public void deletePlaylistUser(int playlistId, String username) {
        update("delete from playlist_user where playlist_id=? and username=?", playlistId, username);
    }

    public synchronized void deletePlaylist(int id) {
        update("delete from playlist where id=?", id);
    }

    public void updatePlaylist(Playlist playlist) {
        update("update playlist set username=?, is_public=?, name=?, changed=? where id=?",
                playlist.getUsername(), playlist.isPublic(), playlist.getName(),
                new Date(), playlist.getId());
    }

    private static class PlaylistMapper implements ParameterizedRowMapper<Playlist> {

        @Override
        public Playlist mapRow(ResultSet rs, int rowNum) throws SQLException 
        {
            Playlist playlist = new Playlist();
            
            playlist.setId(rs.getInt(1));
            playlist.setUsername(rs.getString(2));
            playlist.setPublic(rs.getBoolean(3));
            playlist.setName(rs.getString(4));
            playlist.setElementCount(rs.getInt(5));
            playlist.setDuration(rs.getInt(6));
            playlist.setCreated(rs.getTimestamp(7));
            playlist.setChanged(rs.getTimestamp(8));
            
            return playlist;
        }
    }
}
